package com.sjp.myspring.orm.test;

import com.sjp.myspring.utils.StringUtils;

import javax.persistence.Column;
import javax.persistence.Table;
import java.lang.reflect.Field;
import java.sql.*;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class JdbcTest3 {

    public static void main(String[] args) {
        String sql = "SELECT * FROM book WHERE id = ?";
        List<Book> result = select(Book.class, sql, 3);
        result.forEach(System.out::println);

        Book example = new Book();
        example.setId(20L);
        result = selectByExample(example);
        result.forEach(System.out::println);
    }

    private static <T> List<T> selectByExample(T obj) {
        Class<T> clazz = (Class<T>) obj.getClass();
        String tableName = StringUtils.lowercaseFirst(clazz.getSimpleName());
        if (clazz.isAnnotationPresent(Table.class)) {
            tableName = clazz.getAnnotation(Table.class).name();
        }
        String sql = "SELECT * FROM " + tableName;
        StringBuilder where = new StringBuilder(" WHERE 1=1 ");
        Field[] fields = clazz.getDeclaredFields();
        List<Object> params = new ArrayList<>();
        try {
            for (Field field : fields) {
                field.setAccessible(true);
                Object fieldValue = field.get(obj);
                if (fieldValue != null) {
                    String columnName = field.getName();
                    if (field.isAnnotationPresent(Column.class)) {
                        columnName = field.getAnnotation(Column.class).name();
                    }
                    where.append(" AND ").append(columnName).append("=?");
                    params.add(fieldValue);
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        sql += where.toString();
        return select(clazz, sql, params.toArray());

    }

    private static <T> List<T> select(Class<T> clazz, String sql, Object... params) {

        Map<String, String> mapper = getMapper(clazz);

        List<T> list = new ArrayList<>();
        Connection conn = null;
        PreparedStatement ps = null;
        ResultSet rs = null;
        try {
            //加载驱动类
            Class.forName("com.mysql.jdbc.Driver");
            String url = "jdbc:mysql://localhost:3306/sjp?useSSL=false";
            String username = "root";
            String password = "123456";
            //建立连接
            conn = DriverManager.getConnection(url, username, password);
            //创建语句集
            ps = conn.prepareStatement(sql);

            for (int i = 0; i < params.length; i++) {
                ps.setObject(i + 1, params[i]);
            }


            //执行语句集
            rs = ps.executeQuery();

            int columnCount = rs.getMetaData().getColumnCount();

            while (rs.next()) {
                T t = clazz.newInstance();
                for (int i = 1; i <= columnCount; i++) {
                    String columnName = rs.getMetaData().getColumnName(i);
                    String fieldName = mapper.get(columnName);
                    if (fieldName != null) {
                        Field field = clazz.getDeclaredField(fieldName);
                        field.setAccessible(true);
                        field.set(t, rs.getObject(columnName));
                    }
                }
                list.add(t);
            }


        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            //关闭结果集，语句集，连接
            try {
                rs.close();
                ps.close();
                conn.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }

        }
        return list;
    }

    private static <T> Map<String, String> getMapper(Class<T> clazz) {
        Map<String, String> map = new HashMap<>();
        for (Field field : clazz.getDeclaredFields()) {
            String fieldName = field.getName();
            String tableColumnName = fieldName;
            if (field.isAnnotationPresent(Column.class)) {
                Column column = field.getAnnotation(Column.class);
                tableColumnName = column.name();
            }
            map.put(tableColumnName, fieldName);
        }
        return map;
    }
}
